import * as Cesium from 'cesium'
// https://cesium.com/learn/cesiumjs/ref-doc/BillboardGraphics.html?classFilter=billboard
export class DomEntity {
    constructor(
        {
            parentDom = document.body,
            id,
            position,
            html,
            horizontalOrigin = Cesium.HorizontalOrigin.LEFT,
            verticalOrigin = Cesium.VerticalOrigin.TOP,
            pixelOffset = new Cesium.Cartesian2(0, 0),
            distanceDisplayCondition = new Cesium.DistanceDisplayCondition(),
            scaleByDistance = new Cesium.NearFarScalar(0, 1, 1, 1),
            // TODO: 待实现
            // 从上到下优先级递减
            // sizeInMeters,
            // pixelOffsetScaleByDistance ,
            show = true,
        },

        viewer = window.cesiumViewer
    ) {
        if (!Cesium.defined(html)) {
            throw new Error('未传参html')
        }

        if (!Cesium.defined(position)) {
            throw new Error('未传参 position')
        }

        this._id = id
        this._position = position
        this._html = html
        this._verticalOrigin = verticalOrigin
        this._horizontalOrigin = horizontalOrigin
        this._pixelOffset = pixelOffset
        this._distanceDisplayCondition = distanceDisplayCondition
        this._scaleByDistance = scaleByDistance
        this._show = show
        this.viewer = viewer
        this.rootDom = null
        this.isDestroyed = false
        this.parentDom = parentDom
        this.removeCallback = this.init()
    }

    init() {
        const rootDom = (this.rootDom = document.createElement('div'))

        rootDom.className = 'dom-entity outer'
        rootDom.dataset.id = this._id

        Object.assign(rootDom.style, {
            position: 'fixed',
            pointerEvents: 'none',
            // visibility: 'hidden',
            opacity: 0,
            transform: `translate(${(this._horizontalOrigin - 1) * 50}%,${
                (-this._verticalOrigin - 1) * 50
            }%)`,
        })

        if (typeof this._html === 'string') {
            rootDom.innerHTML = this._html
        } else {
            rootDom.appendChild(this._html)
        }

        this.parentDom.appendChild(rootDom)

        const scratchCartesian2 = new Cesium.Cartesian2()

        return this.viewer.scene.preRender.addEventListener(
            (scene, julianDate) => {
                if (this._show) {
                    const distance = Cesium.Cartesian3.distance(
                        scene.camera.position,
                        this._position
                    )

                    const { near, far } = this._distanceDisplayCondition

                    if (near < distance && distance < far) {
                        if (this.judgeOcclusionByGlobe(this._position, scene)) {
                            rootDom.style.visibility = 'hidden'
                            // rootDom.style.opacity = 0
                        } else {
                            // rootDom.style.visibility = 'visible'

                            this.viewer.scene.cartesianToCanvasCoordinates(
                                this._position,
                                scratchCartesian2
                            )
                            if (Cesium.defined(scratchCartesian2)) {
                                rootDom.style.left = `${
                                    scratchCartesian2.x + this._pixelOffset.x
                                }px`
                                rootDom.style.top = `${
                                    scratchCartesian2.y + this._pixelOffset.y
                                }px`
                            }

                            const { near, nearValue, far, farValue } =
                                this._scaleByDistance

                            let scale = 1.0
                            if (distance < near) {
                                scale = nearValue
                            } else if (distance > far) {
                                scale = farValue
                            } else {
                                scale = Cesium.Math.lerp(
                                    nearValue,
                                    farValue,
                                    (distance - near) / (far - near)
                                )
                            }

                            rootDom.style.transform = `translate(${
                                (this._horizontalOrigin - 1) * 50
                            }%,${
                                (-this._verticalOrigin - 1) * 50
                            }%) scale(${scale})`

                            rootDom.style.opacity = 1
                            // rootDom.style.visibility = 'visible'
                        }
                    } else {
                        // rootDom.style.visibility = 'hidden'
                        rootDom.style.opacity = 0
                    }
                } else {
                    // rootDom.style.visibility = 'hidden'

                    rootDom.style.opacity = 0
                }
            }
        )
    }

    // 判断是否被地球遮挡

    judgeOcclusionByGlobe(position, scene) {
        const occluder = new Cesium.EllipsoidalOccluder(
            Cesium.Ellipsoid.WGS84,
            scene.camera.position
        )
        return !occluder.isPointVisible(position)
    }

    destroy() {
        if (this.isDestroyed) return

        this.removeCallback()

        this.parentDom.removeChild(this.rootDom)
        this.isDestroyed = true
    }
    get show() {
        return this._show
    }
    set show(flag) {
        this._show = flag
        // this.rootDom.style.visibility = flag ? 'visible' : 'hidden'
        this.rootDom.style.opacity = flag ? 1 : 0
    }
}
